home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / usr / share / python-support / gnome-games-data / glchess / ggz / protocol.py < prev   
Encoding:
Python Source  |  2009-04-14  |  20.5 KB  |  707 lines

  1. # -*- coding: utf-8 -*-
  2. import xml.sax.handler
  3.  
  4. "<UPDATE TYPE='player' ACTION='delete' ROOM='40' TOROOM='-1'>"
  5. "<PLAYER ID='kostaya'/>"
  6. "</UPDATE>"
  7.  
  8. "<UPDATE TYPE='table' ACTION='leave' ROOM='40'>"
  9. "<TABLE ID='1' SEATS='2'>"
  10. "<SEAT NUM='0' TYPE='player'>kostaya</SEAT>"
  11. "</TABLE>"
  12. "</UPDATE>"
  13.  
  14. "<UPDATE TYPE='table' ACTION='status' ROOM='40'>"
  15. "<TABLE ID='1' STATUS='3' SEATS='2'/>"
  16. "</UPDATE>"
  17.  
  18. "<UPDATE TYPE='table' ACTION='delete' ROOM='40'>"
  19. "<TABLE ID='1' STATUS='-1' SEATS='2'/>"
  20. "</UPDATE>"
  21.  
  22. class ParserFeedback:
  23.     def onResult(self, action, code):
  24.         pass
  25.     
  26.     def onMOTD(self, motd):
  27.         pass
  28.  
  29.     def onChat(self, chatType, sender, text):
  30.         pass
  31.         
  32.     def onJoin(self, tableId, isSpectator):
  33.         pass
  34.         
  35.     def onLeave(self, reason):
  36.         pass
  37.         
  38.     def gameAdded(self, gameId, name, version, author, url, numPlayers, protocol_engine, protocol_version):
  39.         pass
  40.  
  41.     def roomAdded(self, roomId, gameId, name, description, nPlayers):
  42.         pass
  43.  
  44.     def roomPlayersUpdate(self, roomId, nPlayers):
  45.         pass
  46.  
  47.     def tableAdded(self, roomId, tableId, gameId, status, nSeats, description):
  48.         pass
  49.  
  50.     def tableStatusChanged(self, tableId, status):
  51.         pass
  52.  
  53.     def seatChanged(self, roomId, tableId, seatId, seatType, user):
  54.         pass
  55.  
  56.     def tableRemoved(self, tableId):
  57.         pass
  58.  
  59.     def onPlayerList(self, room, players):
  60.         pass
  61.  
  62.     def playerAdded(self, name, playerType, tableId, perms, lag, room, fromRoom):
  63.         pass
  64.  
  65.     def playerRemoved(self, name, room, toRoom):
  66.         pass
  67.  
  68. class GGZParser:
  69.     """
  70.     """
  71.     parent = None
  72.  
  73.     parser = None
  74.     
  75.     def startElement(self, name, attributes):
  76.         if self.parser is not None:
  77.             self.parser.startElement(name, attributes)
  78.             return
  79.         try:
  80.             method = getattr(self, 'start_%s' % name.lower())
  81.         except AttributeError:
  82.             print 'Unknown start element: %s' % name
  83.         else:
  84.             method(attributes)
  85.  
  86.     def characters(self, data):
  87.         if self.parser is not None:
  88.             self.parser.characters(data)
  89.             return
  90.         self.handle_data(data)
  91.     
  92.     def endElement(self, name):
  93.         if self.parser is not None:
  94.             self.parser.endElement(name)
  95.             return
  96.         try:
  97.             method = getattr(self, 'end_%s' % name.lower())
  98.         except AttributeError:
  99.             print 'Unknown end element: %s' % name
  100.         else:
  101.             method()
  102.             
  103.     def push(self, parser, attributes):
  104.         assert(self.parser is None)
  105.         parser.attributes = attributes
  106.         parser.decoder = self.decoder
  107.         parser.parent = self
  108.         self.parser = parser
  109.         
  110.     def pop(self):
  111.         assert(self.parent is not None)
  112.         parser = self.parent.parser
  113.         self.parent.parser = None
  114.         self.parent.childFinished(parser)
  115.  
  116.     def handle_data(self, data):
  117.         pass
  118.     
  119.     def childFinished(self, parser):
  120.         pass
  121.     
  122. class GameParser(GGZParser):
  123.     """
  124.     <GAME ID='24' NAME='TicTacToe' VERSION='0.0.9'>
  125.     <PROTOCOL ENGINE='TicTacToe' VERSION='4'/>
  126.     <ALLOW PLAYERS='2' BOTS='1' SPECTATORS='true' PEERS='false'/>
  127.     <BOT NAME='Alfred' CLASS='easy'/>
  128.     <BOT NAME='Tarantula' CLASS='hard'/>
  129.     <ABOUT AUTHOR='Brent Hendricks' URL='http://www.ggzgamingzone.org/games/tictactoe/'/>
  130.     <DESC>Simple GGZ game module for playing Tic-Tac-Toe</DESC>
  131.     </GAME>
  132.     """
  133.     
  134.     def __init__(self):
  135.         self.bots = []
  136.     
  137.     def start_desc(self, attributes):
  138.         self.push(DescriptionParser(), attributes)
  139.         
  140.     def start_protocol(self, attributes):
  141.         self.push(GameProtocolParser(), attributes)
  142.  
  143.     def start_allow(self, attributes):
  144.         self.push(GameAllowParser(), attributes)
  145.         
  146.     def start_bot(self, attributes):
  147.         self.push(GameBotParser(), attributes)
  148.     
  149.     def start_about(self, attributes):
  150.         self.push(GameAboutParser(), attributes)
  151.  
  152.     def end_game(self):
  153.         self.gameId = self.attributes['ID']
  154.         self.name = self.attributes['NAME']
  155.         self.version = self.attributes['VERSION']
  156.         self.pop()
  157.  
  158.     def __str__(self):
  159.         return 'GGZ Game id=%s protocol=%s (%s) description=%s' % (self.gameId, repr(self.protocol.engine), self.protocol.version, repr(self.description))
  160.     
  161. class DescriptionParser(GGZParser):
  162.     """   
  163.     <DESC>Simple GGZ game module for playing Tic-Tac-Toe</DESC>
  164.     """
  165.  
  166.     def handle_data(self, data):
  167.         self.parent.description = data
  168.         
  169.     def end_desc(self):
  170.         self.pop()
  171.  
  172. class GameProtocolParser(GGZParser):
  173.     """
  174.     <PROTOCOL ENGINE='TicTacToe' VERSION='4'/>
  175.     """
  176.     
  177.     def end_protocol(self):
  178.         self.parent.protocol = self
  179.         self.engine = self.attributes['ENGINE']
  180.         self.version = self.attributes['VERSION']
  181.         self.pop()
  182.  
  183. class GameAllowParser(GGZParser):
  184.     """
  185.     <ALLOW PLAYERS='2' BOTS='1' SPECTATORS='true' PEERS='false'/>
  186.     """
  187.     
  188.     def end_allow(self):
  189.         self.parent.allow = self
  190.         self.numPlayers = self.attributes['PLAYERS']
  191.         self.pop()
  192.  
  193. class GameBotParser(GGZParser):
  194.     """
  195.     <BOT NAME='Alfred' CLASS='easy'/>
  196.     <BOT NAME='Tarantula' CLASS='hard'/>
  197.     """
  198.     
  199.     def end_bot(self):
  200.         self.parent.bots.append(self)
  201.         self.name = self.attributes['NAME']
  202.         self.difficulty = self.attributes['CLASS']
  203.         self.pop()
  204.  
  205. class GameAboutParser(GGZParser):
  206.     """
  207.     <ABOUT AUTHOR='Brent Hendricks' URL='http://www.ggzgamingzone.org/games/tictactoe/'/>
  208.     """
  209.  
  210.     def end_about(self):
  211.         self.parent.about = self
  212.         self.author = self.attributes['AUTHOR']
  213.         self.url = self.attributes['URL']
  214.         self.pop()
  215.  
  216. class RoomParser(GGZParser):
  217.     
  218.     def start_desc(self, attributes):
  219.         self.push(DescriptionParser(), attributes)
  220.  
  221.     def end_room(self):
  222.         self.pop()
  223.     
  224.     def __str__(self):
  225.         return 'GGZ Room id=%s game=%s description=%s' % (self.roomId, self.game, repr(self.description))
  226.  
  227. class PlayerParser(GGZParser):
  228.  
  229.     def end_player(self):
  230.         self.pop()
  231.         
  232.     def __str__(self):
  233.         return 'GGZ Player id=%s type=%s table=%s perms=%s lag=%s' % (self.id, self.type, self.table, self.perms, self.lag)
  234.     
  235. class TableSeatParser(GGZParser):
  236.     
  237.     def __init__(self):
  238.         self.label = ''
  239.  
  240.     def handle_data(self, data):
  241.         self.label += data
  242.  
  243.     def end_seat(self):
  244.         self.pop()
  245.  
  246. class TableParser(GGZParser):
  247.     
  248.     def __init__(self):
  249.         self.seats = []
  250.         self.description = ''
  251.  
  252.     def start_desc(self, attributes):
  253.         self.push(DescriptionParser(), attributes)
  254.  
  255.     def start_seat(self, attributes):
  256.         self.push(TableSeatParser(), attributes)
  257.  
  258.     def childFinished(self, parser):
  259.         if isinstance(parser, TableSeatParser):
  260.             self.seats.append(parser)
  261.  
  262.     def end_table(self):
  263.         self.pop()
  264.  
  265. class GameListParser(GGZParser):
  266.     
  267.     def __init__(self):
  268.         self.games = []
  269.     
  270.     def start_game(self, attributes):
  271.         self.push(GameParser(), attributes)
  272.  
  273.     def childFinished(self, parser):
  274.         self.games.append(parser)
  275.  
  276.     def end_list(self):
  277.         for g in self.games:
  278.             self.decoder.feedback.gameAdded(g.gameId, g.name, g.version, g.about.author, g.about.url, g.allow.numPlayers,
  279.                                               g.protocol.engine, g.protocol.version)
  280.         self.pop()
  281.       
  282. class TableListParser(GGZParser):
  283.     
  284.     def __init__(self):
  285.         self.tables = []
  286.     
  287.     def start_table(self, attributes):
  288.         self.push(TableParser(), attributes)
  289.  
  290.     def childFinished(self, parser):
  291.         self.tables.append(parser)
  292.  
  293.     def end_list(self):
  294.         for t in self.tables:
  295.             room = self.attributes['ROOM']
  296.             tableId = t.attributes['ID']
  297.             gameId = t.attributes['GAME']
  298.             status = t.attributes['STATUS']
  299.             nSeats = int(t.attributes['SEATS'])
  300.             self.decoder.feedback.tableAdded(room, tableId, gameId, status, nSeats, t.description)
  301.             for seat in t.seats:
  302.                 self.decoder.feedback.seatChanged(room, tableId, seat.attributes['NUM'], seat.attributes['TYPE'], seat.label)
  303.         self.pop()
  304.  
  305. class PlayerListParser(GGZParser):
  306.     
  307.     def __init__(self):
  308.         self.players = []
  309.     
  310.     def start_player(self, attributes):
  311.         self.push(PlayerParser(), attributes)
  312.  
  313.     def childFinished(self, playerParser):
  314.         playerParser.name = playerParser.attributes['ID']
  315.         playerParser.type = playerParser.attributes['TYPE']
  316.         playerParser.tableId = playerParser.attributes['TABLE']
  317.         try:
  318.             playerParser.perms = playerParser.attributes['PERMS']
  319.         except KeyError:
  320.             playerParser.perms = ''
  321.         playerParser.lag = playerParser.attributes['LAG']
  322.         self.players.append(playerParser)
  323.  
  324.     def end_list(self):
  325.         self.decoder.feedback.onPlayerList(self.attributes['ROOM'], self.players)
  326.         self.pop()
  327.  
  328. class RoomListParser(GGZParser):
  329.     
  330.     def __init__(self):
  331.         self.rooms = []
  332.         
  333.     def start_room(self, attributes):
  334.         self.push(RoomParser(), attributes)
  335.  
  336.     def childFinished(self, parser):
  337.         parser.roomId = parser.attributes['ID']
  338.         parser.name = parser.attributes['NAME']
  339.         parser.game = parser.attributes['GAME']
  340.         parser.nPlayers = int(parser.attributes['PLAYERS'])
  341.         self.rooms.append(parser)
  342.  
  343.     def end_list(self):
  344.         for r in self.rooms:
  345.             self.decoder.feedback.roomAdded(r.roomId, r.game, r.name, r.description, r.nPlayers)
  346.         self.pop()
  347.         
  348. class ServerOptionsParser(GGZParser):
  349.  
  350.     def end_options(self):
  351.         self.pop()
  352.         
  353. class ServerParser(GGZParser):
  354.     
  355.     def start_options(self, attributes):
  356.         self.push(ServerOptionsParser(), attributes)
  357.     
  358.     def end_server(self):
  359.         self.decoder.feedback.onConnected()
  360.         self.pop()
  361.  
  362. class MOTDParser(GGZParser):
  363.     
  364.     def __init__(self):
  365.         self.motd = ''
  366.     
  367.     def handle_data(self, data):
  368.         self.motd += data
  369.     
  370.     def end_motd(self):
  371.         self.decoder.feedback.onMOTD(self.motd)
  372.         self.pop()
  373.  
  374. class RoomUpdateParser(GGZParser):
  375.     
  376.     def __init__(self):
  377.         pass
  378.     
  379.     def start_room(self, attributes):
  380.         self.push(RoomParser(), attributes)
  381.         
  382.     def childFinished(self, parser):
  383.         action = self.attributes['ACTION'].lower()
  384.         if action == 'players':
  385.             roomId = parser.attributes['ID']
  386.             nPlayers = int(parser.attributes['PLAYERS'])
  387.             self.decoder.feedback.roomPlayersUpdate(roomId, nPlayers)
  388.         else:
  389.             print 'Unknown player update action %s' % action
  390.     
  391.     def end_update(self):
  392.         self.pop()
  393.  
  394. class PlayerUpdateParser(GGZParser):
  395.     
  396.     def start_player(self, attributes):
  397.         self.push(PlayerParser(), attributes)
  398.  
  399.     def childFinished(self, parser):
  400.         action = self.attributes['ACTION'].lower()
  401.         if action == 'add':
  402.             name = parser.attributes['ID']
  403.             playerType = parser.attributes['TYPE']
  404.             table = parser.attributes['TABLE']
  405.             try:
  406.                 perms = parser.attributes['PERMS']
  407.             except KeyError:
  408.                 perms = ''
  409.             lag = parser.attributes['LAG']
  410.             roomId = self.attributes['ROOM']
  411.             fromRoomId = self.attributes['FROMROOM']
  412.             self.decoder.feedback.playerAdded(name, playerType, table, perms, lag, roomId, fromRoomId)
  413.         elif action == 'lag':
  414.             playerId = parser.attributes['ID']
  415.             lag = parser.attributes['LAG']
  416.             print 'Player %s lag changed to %s' % (playerId, lag)
  417.         elif action == 'join':
  418.             pass
  419.         elif action == 'leave':
  420.             pass
  421.         elif action == 'desc':
  422.             pass
  423.         elif action == 'seat':
  424.             pass
  425.         elif action == 'delete':
  426.             playerId = parser.attributes['ID']
  427.             room = self.attributes['ROOM']
  428.             toRoom = self.attributes['TOROOM']
  429.             self.decoder.feedback.playerRemoved(playerId, room, toRoom)
  430.         else:
  431.             print 'Unknown player update action %s' % action
  432.     
  433.     def end_update(self):
  434.         self.pop()
  435.         
  436. class TableUpdateParser(GGZParser):   
  437.  
  438.     def __init__(self):
  439.         self.table = None
  440.     
  441.     def start_table(self, attributes):
  442.         self.push(TableParser(), attributes)
  443.         
  444.     def childFinished(self, parser):
  445.         self.table = parser
  446.  
  447.     def end_update(self):
  448.         room = self.attributes['ROOM']        
  449.         action = self.attributes['ACTION']
  450.         if action == 'add':
  451.              "<UPDATE TYPE='table' ACTION='add' ROOM='3'>"
  452.              " <TABLE ID='1' GAME='30' STATUS='1' SEATS='2'>"
  453.              "  <DESC></DESC>"
  454.              "  <SEAT NUM='0' TYPE='reserved'>bob</SEAT>"
  455.              "  <SEAT NUM='1' TYPE='bot'/>"
  456.              " </TABLE>"
  457.              "</UPDATE>"
  458.              room = self.attributes['ROOM']
  459.              tableId = self.table.attributes['ID']
  460.              gameId = self.table.attributes['GAME']
  461.              status = self.table.attributes['STATUS']
  462.              nSeats = int(self.table.attributes['SEATS'])
  463.              description = self.table.description
  464.              # FIXME: Include the seats with the add event somehow (and other adds)
  465.              self.decoder.feedback.tableAdded(room, tableId, gameId, status, nSeats, description)
  466.              for seat in self.table.seats:
  467.                  self.decoder.feedback.seatChanged(room, tableId, seat.attributes['NUM'], seat.attributes['TYPE'], seat.label)
  468.  
  469.         elif action == 'join':
  470.             "<UPDATE TYPE='table' ACTION='join' ROOM='3'>"
  471.             " <TABLE ID='1' SEATS='2'>"
  472.             "  <SEAT NUM='0' TYPE='player'>bob</SEAT>"
  473.             " </TABLE>"
  474.             "</UPDATE>"
  475.             room = self.attributes['ROOM']
  476.             tableId = self.table.attributes['ID']
  477.             for seat in self.table.seats:
  478.                 self.decoder.feedback.seatChanged(room, tableId, seat.attributes['NUM'], seat.attributes['TYPE'], seat.label)
  479.  
  480.         elif action == 'leave':
  481.             "<UPDATE TYPE='table' ACTION='leave' ROOM='3'>"
  482.             " <TABLE ID='1' SEATS='2'>"
  483.             "  <SEAT NUM='0' TYPE='player'>bob</SEAT>"
  484.             " </TABLE>"
  485.             "</UPDATE>"
  486.             room = self.attributes['ROOM']
  487.             tableId = self.table.attributes['ID']
  488.             for seat in self.table.seats:
  489.                 self.decoder.feedback.seatChanged(room, tableId, seat.attributes['NUM'], seat.attributes['TYPE'], '') # seat.label)???
  490.  
  491.         elif action == 'status':
  492.             "<UPDATE TYPE='table' ACTION='status' ROOM='3'>"
  493.             " <TABLE ID='1' STATUS='3' SEATS='2'/>"
  494.             "</UPDATE>"
  495.             self.decoder.feedback.tableStatusChanged(self.table.attributes['ID'], self.table.attributes['STATUS'])
  496.  
  497.         elif action == 'delete':
  498.             "<UPDATE TYPE='table' ACTION='delete' ROOM='3'>"
  499.             " <TABLE ID='1' STATUS='-1' SEATS='2'/>"
  500.             "</UPDATE>"
  501.             self.decoder.feedback.tableRemoved(self.table.attributes['ID'])
  502.  
  503.         else:
  504.             print 'Unknown table update action: %s' % action
  505.  
  506.         self.pop()
  507.     
  508.     "<UPDATE TYPE='table' ACTION='add' ROOM='13'>"
  509.     " <TABLE ID='1' GAME='24' STATUS='1' SEATS='4'>"
  510.     "  <DESC>I play alone...</DESC>"
  511.     "  <SEAT NUM='0' TYPE='reserved'>helg</SEAT>"
  512.     "  <SEAT NUM='1' TYPE='bot'/>"
  513.     "  <SEAT NUM='2' TYPE='bot'/>"
  514.     "  <SEAT NUM='3' TYPE='bot'/>"
  515.     " </TABLE>"
  516.     "</UPDATE>"
  517.     "<UPDATE TYPE='table' ACTION='join' ROOM='13'>"
  518.     " <TABLE ID='1' SEATS='4'>"
  519.     "  <SEAT NUM='0' TYPE='player'>helg</SEAT>"
  520.     " </TABLE>"
  521.     "</UPDATE>"
  522.  
  523. class ChatParser(GGZParser):
  524.     
  525.     def __init__(self):
  526.         self.text = ''
  527.     
  528.     def handle_data(self, data):
  529.         self.text += data
  530.  
  531.     def end_chat(self):
  532.         chatType = self.attributes['TYPE']
  533.         sender = self.attributes['FROM']
  534.         self.decoder.feedback.onChat(chatType, sender, self.text)
  535.         self.pop()
  536.  
  537. class ResultParser(GGZParser):
  538.     
  539.     def start_list(self, attributes):
  540.         t = attributes['TYPE'].lower()
  541.         if t == 'player':
  542.             self.push(PlayerListParser(), attributes)
  543.         elif t == 'room':
  544.             self.push(RoomListParser(), attributes)
  545.         elif t == 'game':
  546.             self.push(GameListParser(), attributes)
  547.         elif t == 'table':
  548.             self.push(TableListParser(), attributes)
  549.         else:
  550.             print 'Unknown list: %s' % t
  551.  
  552.     def end_result(self):
  553.         action = self.attributes['ACTION']
  554.         code = self.attributes['CODE']
  555.         self.decoder.feedback.onResult(action, code)
  556.         self.pop()
  557.         
  558. class JoinParser(GGZParser):
  559.     
  560.     def end_join(self):
  561.         tableId = self.attributes['TABLE']
  562.         isSpectator = self.attributes['SPECTATOR'] == 'true'
  563.         self.decoder.feedback.onJoin(tableId, isSpectator)
  564.         self.pop()
  565.  
  566. class LeaveParser(GGZParser):
  567.     "<LEAVE REASON='gameover'/>"
  568.     
  569.     def end_leave(self):
  570.         reason = self.attributes['REASON']
  571.         self.decoder.feedback.onLeave(reason)
  572.         self.pop()
  573.  
  574. class SessionParser(GGZParser):
  575.     
  576.     def start_server(self, attributes):
  577.         self.push(ServerParser(), attributes)
  578.     
  579.     def start_motd(self, attributes):
  580.         self.push(MOTDParser(), attributes)
  581.  
  582.     def start_update(self, attributes):
  583.         t = attributes['TYPE'].lower()
  584.         if t == 'room':
  585.             self.push(RoomUpdateParser(), attributes)
  586.         elif t == 'player':
  587.             self.push(PlayerUpdateParser(), attributes)
  588.         elif t == 'table':
  589.             self.push(TableUpdateParser(), attributes)
  590.         else:
  591.             print 'Unknown update type: %s' % t
  592.             
  593.     def start_join(self, attributes):
  594.         self.push(JoinParser(), attributes)
  595.         
  596.     def start_leave(self, attributes):
  597.         self.push(LeaveParser(), attributes)
  598.  
  599.     def start_result(self, attributes):
  600.         self.push(ResultParser(), attributes)
  601.         
  602.     def start_chat(self, attributes):
  603.         self.push(ChatParser(), attributes)
  604.     
  605.     def start_ping(self, attributes):
  606.         self.decoder.feedback.send("<PONG/>\n")
  607.         
  608.     def end_ping(self):
  609.         pass
  610.  
  611.     def end_session(self):
  612.         self.decoder.feedback.onSessionEnded()
  613.         pass
  614.  
  615. class BaseParser(GGZParser):
  616.     
  617.     def __init__(self, decoder):
  618.         self.decoder = decoder
  619.  
  620.     def start_session(self, attributes):
  621.         self.push(SessionParser(), attributes)
  622.  
  623. class Decoder(xml.sax.handler.ContentHandler):
  624.  
  625.     def __init__(self, feedback):
  626.         xml.sax.handler.ContentHandler.__init__(self)
  627.         self.feedback = feedback
  628.         self.parser = None
  629.         self.xparser = xml.sax.make_parser()
  630.         self.handler = BaseParser(self)
  631.         self.xparser.setContentHandler(self)
  632.  
  633.     def startElement(self, name, attributes):
  634.         self.handler.startElement(name, attributes)
  635.  
  636.     def characters(self, data):
  637.         self.handler.characters(data)
  638.  
  639.     def endElement(self, name):
  640.         self.handler.endElement(name)
  641.  
  642.     def feed(self, data):
  643.         """Feed data into the decoder.
  644.         
  645.         'data' is the raw data to feed.
  646.         
  647.         Returns the next block of data to process, keep feeding until '' is returned.
  648.         """
  649.         index = data.find('\n')
  650.         if index < 0:
  651.             index = len(data) - 1
  652.  
  653.         chunk = data[:index+1]
  654.         try:
  655.             self.xparser.feed(chunk)
  656.         except xml.sax.SAXParseException:
  657.             print 'Invalid XML: %s' % repr(chunk)
  658.         return data[index+1:]
  659.  
  660. if __name__ == '__main__':
  661.     import chess
  662.     
  663.     class F:
  664.         
  665.         def onSeat(self, seatNum, version):
  666.             print ('onSeat', seatNum, version)
  667.             
  668.         def onPlayers(self, whiteType, whiteName, blackType, blackName):
  669.             print ('onPlayers', whiteType, whiteName, blackType, blackName)
  670.                 
  671.         def onTimeRequest(self):
  672.             print ('onTimeRequest',)
  673.     
  674.         def onSetTime(self, time):
  675.             print ('onSetTime', time)
  676.  
  677.         def onStart(self):
  678.             print ('onStart',)
  679.     
  680.         def onMove(self, move):
  681.             print ('onMove', move)    
  682.  
  683.     f = F()
  684.     d = chess.Chess(f);
  685.  
  686.     data = '\x01\x01\x06' # Seat seat=1 version=6
  687.     for c in data:
  688.         d.decode(c)
  689.         
  690.     data = '\x02\x03\x00\x00\x00\x0eglchess-test2\x00\x03\x00\x00\x00\x0dglchess-test\x00' # players type1=03 name1=glchess-test2 type2=03 name2=glchess-test
  691.     for c in data:
  692.         d.decode(c)
  693.  
  694.     data = '\x04\x00\x00\x00\x00'  # rsp time time=0
  695.     for c in data:
  696.         d.decode(c)
  697.  
  698.     d.decode('\x05') # start
  699.  
  700.     data = '\x07\x00\x00\x00\x05F2F4\x00' # move move=F2F4
  701.     for c in data:
  702.         d.decode(c)
  703.  
  704.     data = '\x0a\x00\x00\x00\x00\x00\x00\x00\x00' # update
  705.     for c in data:
  706.         d.decode(c)
  707.